home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / bmutil.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  24KB  |  1,025 lines

  1. /*
  2.  *    Simple mail user interface for KA9Q IP/TCP package.
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *    Copyright 1987 1988 Dave Trulli NN2Z, All Rights Reserved.
  8.  *    Permission granted for non-commercial copying and use, provided
  9.  *    this notice is retained.
  10.  *
  11.  *    Ported to NOS at 900120 by Anders Klemets SM0RGV.
  12.  *
  13.  * ST NOS Version by David Nash
  14.  */
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <ctype.h>
  18. #include <time.h>
  19. #include "global.h"
  20. #include "ftpserv.h"
  21. #include "smtp.h"
  22. #include "proc.h"
  23. #include "usock.h"
  24. #include "socket.h"
  25. #include "telnet.h"
  26. #include "timer.h"
  27. #include "session.h"
  28. #include "files.h"
  29.  
  30. #define        SETVBUF
  31. #if    defined(UNIX) || defined(MICROSOFT)
  32. #include    <sys/types.h>
  33. #endif
  34. /*
  35. #if    defined(UNIX) || defined(MICROSOFT) || defined(__TURBOC__)
  36. #include    <sys/stat.h>
  37. #endif
  38. #ifdef AZTEC
  39. #include <stat.h>
  40. #endif
  41. */
  42. #ifndef ATARI
  43. #include <fcntl.h>
  44. #endif
  45. #include "bm.h"
  46. #include "mailbox.h"
  47.  
  48. #ifdef SETVBUF
  49. #define        MYBUF    1024
  50. #endif
  51.  
  52. void scanmail(struct mbx *m);
  53.  
  54. extern long ftell();
  55. static char Badmsg[] = "Invalid Message number %d\n";
  56. static char Nomail[] = "No messages\n";
  57. static char Noaccess[] = "Unable to access %s\n";
  58. static int readnotes __ARGS((struct mbx *m,FILE *ifile,int update));
  59. static long isnewmail __ARGS((struct mbx *m));
  60. static int initnotes __ARGS((struct mbx *m));
  61. static int lockit __ARGS((struct mbx *m));
  62. static long fsize __ARGS((char *name));
  63. static void mfclose __ARGS((struct mbx *m));
  64. static int tkeywait __ARGS((char *prompt,int flush));
  65.  
  66. static int initnotes(struct mbx *m)
  67. {
  68. #ifndef ATARI    
  69.     FILE    *tmpfile();
  70. #endif    
  71.     FILE    *ifile;
  72.     register struct    let *cmsg;
  73.     char buf[256];
  74.     int     i, ret;
  75.  
  76.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  77.     if ((ifile = fopen(buf,READ_TEXT)) == NULLFILE)
  78.         return 0;
  79.     fseek(ifile,0L,2);     /* go to end of file */
  80.     m->mboxsize = ftell(ifile);
  81.     rewind(ifile);
  82.     if(!stricmp(m->area,m->name)) /* our private mail area */
  83.         m->mysize = m->mboxsize;
  84.     if ((m->mfile = tmpfile()) == NULLFILE) {
  85.         (void) fclose(ifile);
  86.         return -1;
  87.     }
  88. #ifdef    SETVBUF
  89.     if (m->stdinbuf == NULLCHAR)
  90.         m->stdinbuf = mallocw(MYBUF);
  91.     setvbuf(ifile, m->stdinbuf, _IOFBF, MYBUF);
  92.     if (m->stdoutbuf == NULLCHAR)
  93.         m->stdoutbuf = mallocw(MYBUF);
  94.     setvbuf(m->mfile, m->stdoutbuf, _IOFBF, MYBUF);
  95. #endif
  96.     m->nmsgs = 0;
  97.     m->current = 0;
  98.     m->change = 0;
  99.     m->newmsgs = 0;
  100.     m->anyread = 0;
  101.     /* Allocate space for reading messages */
  102.     free((char *)m->mbox);
  103.     m->mbox = (struct let *)callocw(Maxlet+1,sizeof(struct let));
  104.     ret = readnotes(m,ifile,0);
  105.     (void) fclose(ifile);
  106. #ifdef SETVBUF
  107.     free(m->stdinbuf);
  108.     m->stdinbuf = NULLCHAR;
  109. #endif
  110.     if (ret != 0)
  111.         return -1;
  112.     for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++)  
  113.         if ((cmsg->status & BM_READ) == 0) {
  114.             m->newmsgs++;
  115.             if (m->current == 0)
  116.                 m->current = i;
  117.         }
  118.     /* start at one if no new messages */
  119.     if (m->current == 0)
  120.         m->current++;
  121.  
  122.     return 0;
  123. }
  124.  
  125. /* readnotes assumes that ifile is pointing to the first
  126.  * message that needs to be read.  For initial reads of a
  127.  * notesfile, this will be the beginning of the file.  For
  128.  * rereads when new mail arrives, it will be the first new
  129.  * message.
  130.  */
  131. static int readnotes(struct mbx *m,FILE *ifile,int update)
  132. {
  133.     char     tstring[LINELEN];
  134.     long    cpos;
  135.     register struct    let *cmsg;
  136.     register char *line;
  137.  
  138.     cmsg = (struct let *)NULL;
  139.     line = tstring;
  140.     while(fgets(line,LINELEN,ifile) != NULLCHAR) {
  141.         /* scan for begining of a message */
  142.         if(strncmp(line,"From ",5) == 0) {
  143.             pwait(NULL);
  144.             cpos = ftell(m->mfile);
  145.             fputs(line,m->mfile);
  146.             if (m->nmsgs == Maxlet) {
  147.                 tprintf("Mail box full: > %d messages\n",Maxlet);
  148.                 mfclose(m);
  149.                 return -1;
  150.             }
  151.             m->nmsgs++;
  152.             cmsg = &m->mbox[m->nmsgs];
  153.             cmsg->start = cpos;
  154.             if(!update)
  155.                 cmsg->status = 0;
  156.             cmsg->size = strlen(line);
  157.             while (fgets(line,LINELEN,ifile) != NULLCHAR) {
  158.                 if (*line == '\n') { /* done header part */
  159.                     cmsg->size++;
  160.                     putc(*line, m->mfile);
  161.                     break;
  162.                 }
  163.                 if (htype(line) == STATUS) {
  164.                     if (line[8] == 'R') 
  165.                         cmsg->status |= BM_READ;
  166.                     continue;
  167.                 }
  168.                 cmsg->size += strlen(line);
  169.                 if (fputs(line,m->mfile) == EOF) {
  170.                     tprintf("tmp file: %s",strerror(errno));
  171.                     mfclose(m);
  172.                     return -1;
  173.                 }
  174.  
  175.             }
  176.         } else if (cmsg) {
  177.             cmsg->size += strlen(line);
  178.             fputs(line,m->mfile);
  179.         }
  180.     }
  181.     return 0;
  182. }
  183.  
  184. /* list headers of a notesfile a message */
  185. int
  186. dolistnotes(argc,argv,p)
  187. int argc;
  188. char *argv[];
  189. void *p;
  190. {
  191.     struct mbx *m;
  192.     register struct    let *cmsg;
  193.     register char    *cp, *s;
  194.     char    smtp_date[SLINELEN], smtp_from[SLINELEN];
  195.     char    smtp_subject[SLINELEN], tstring[LINELEN], type;
  196.     int    start, stop;
  197.     long    size;
  198.     char    *area;
  199.  
  200.     m = (struct mbx *) p;
  201.     if (m->mfile == NULLFILE) {
  202.         tprintf(Nomail);
  203.         return 0;
  204.     }
  205.  
  206.     area = strdup(m->area);
  207.     while((cp = strchr(area,'/')) != NULLCHAR)
  208.         *cp = '.';
  209.     tprintf("Mail area: %s  %d message%s -  %d new\n\n",area,m->nmsgs,
  210.         m->nmsgs == 1 ? " " : "s ", m->newmsgs);
  211.     free(area);
  212.  
  213.     stop = m->nmsgs;
  214.     if(m->stype == 'L') {        /* LL (List Latest) command */
  215.          if(argc > 1)
  216.           start = stop - atoi(argv[1]) + 1;
  217.          else
  218.           start = stop;
  219.     }
  220.     else {
  221.          if(argc > 1)
  222.           start = atoi(argv[1]);
  223.          else
  224.           start = 1;
  225.          if(argc > 2)
  226.           stop = atoi(argv[2]);
  227.     }
  228.     if(stop > m->nmsgs)
  229.         stop = m->nmsgs;
  230.     if(start < 1 || start > stop) {
  231.         tprintf("Invalid range.\n");
  232.         return 0;
  233.     }
  234.     for (cmsg = &m->mbox[start]; start <= stop; start++, cmsg++) {
  235.         *smtp_date = '\0';
  236.         *smtp_from = '\0';
  237.         *smtp_subject = '\0';
  238.         type = ' ';
  239.         fseek(m->mfile,cmsg->start,0);
  240.         size = cmsg->size;
  241.         while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
  242.                != NULLCHAR) {
  243.             if (*tstring == '\n')    /* end of header */
  244.                 break;
  245.             size -= strlen(tstring);
  246.             rip(tstring);
  247.             /* handle continuation later */
  248.             if (*tstring == ' '|| *tstring == '\t')
  249.                 continue;
  250.             switch(htype(tstring)) {
  251.             case FROM:
  252.                 cp = getaddress(tstring,0);
  253.                 sprintf(smtp_from,"%.30s",
  254.                     cp != NULLCHAR ? cp : "");
  255.                 break;
  256.             case SUBJECT:
  257.                 sprintf(smtp_subject,"%.34s",&tstring[9]);
  258.                 break;
  259.             case DATE:
  260.                 if ((cp = strchr(tstring,',')) == NULLCHAR)
  261.                     cp = &tstring[6];
  262.                 else
  263.                     cp++;
  264.                 /* skip spaces */
  265.                 while (*cp == ' ') cp++;
  266.                 if(strlen(cp) < 17)
  267.                     break;     /* not a valid length */
  268.                 s = smtp_date;
  269.                 /* copy day */
  270.                 if (atoi(cp) < 10 && *cp != '0') {
  271.                     *s++ = ' ';
  272.                 } else
  273.                     *s++ = *cp++;
  274.                 *s++ = *cp++;
  275.  
  276.                 *s++ = ' ';
  277.                 *s = '\0';
  278.                 while (*cp == ' ')
  279.                     cp++;
  280.                 strncat(s,cp,3);    /* copy month */
  281.                 cp += 3;
  282.                 while (*cp == ' ')
  283.                     cp++;
  284.                 /* skip year */
  285.                 while (isdigit(*cp))
  286.                     cp++;
  287.                 /* copy time */
  288.                 strncat(s,cp,6); /* space hour : min */
  289.                 break;
  290.             case BBSTYPE:
  291.                 type = tstring[16];
  292.                 break;
  293.             case NOHEADER:
  294.                 break;
  295.             }
  296.         }
  297.         if((type == m->stype && m->stype != ' ') || m->stype == ' '
  298.            || m->stype == 'L')
  299.              tprintf("%c%c%c%3d %-27.27s %-12.12s %5ld %.25s\n",
  300.                  (start == m->current ? '>' : ' '),
  301.                  (cmsg->status & BM_DELETE ? 'D' : ' '),
  302.                  (cmsg->status & BM_READ ? 'Y' : 'N'),
  303.                  start, smtp_from, smtp_date,
  304.                  cmsg->size, smtp_subject);
  305.     }
  306.     return 0;
  307. }
  308.  
  309. /*  save msg on stream - if noheader set don't output the header */
  310. int msgtofile(struct mbx *m,int msg,FILE *tfile,int noheader)
  311. {
  312.     char    tstring[LINELEN];
  313.     long     size;
  314.  
  315.     if (m->mfile == NULLFILE) {
  316.         tprintf(Nomail);
  317.         return -1;
  318.     }
  319.     fseek(m->mfile,m->mbox[msg].start,0);
  320.     size = m->mbox[msg].size;
  321.  
  322.     if (noheader) {
  323.         /* skip header */
  324.         while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
  325.                != NULLCHAR) {
  326.             size -= strlen(tstring);
  327.             if (*tstring == '\n')
  328.                 break;
  329.         }
  330.     }
  331.     while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
  332.            != NULLCHAR) {
  333.         size -= strlen(tstring);
  334.         fputs(tstring,tfile);
  335.         if (ferror(tfile)) {
  336.             tprintf("Error writing mail file\n");
  337.             return -1;
  338.         }
  339.     }
  340.     return 0;
  341. }
  342.  
  343. /*  dodelmsg - delete message in current notesfile */
  344. int
  345. dodelmsg(argc,argv,p)
  346. int argc;
  347. char *argv[];
  348. void *p;
  349. {
  350.     struct mbx *m;
  351.     int msg,i;
  352.     m = (struct mbx *) p;
  353.     if (m->mfile == NULLFILE) {
  354.         tprintf(Nomail);
  355.         return 0;
  356.     }
  357.     for(i = 1; i < argc; ++i) {
  358.         msg = atoi(argv[i]);
  359.         if(msg < 0 || msg > m->nmsgs) {
  360.             tprintf(Badmsg,msg);
  361.             continue;
  362.         }
  363.         /* Check if we have permission to delete others mail */
  364.         if(!(m->privs & FTP_WRITE) && stricmp(m->area,m->name)) {
  365.             tprintf(Noperm);
  366.             return 0;
  367.         }
  368.         m->mbox[msg].status |= BM_DELETE;
  369.         tprintf("Msg %d Killed.\n", msg);
  370.         m->change = 1;
  371.     }
  372.     return 0;
  373. }
  374. /* close the temp file while coping mail back to the mailbox */
  375. int closenotes(struct mbx *m)
  376. {
  377.     register struct    let *cmsg;
  378.     register char *line;
  379.     char tstring[LINELEN], buf[256];
  380.     long size;
  381.     int i, nostatus = 0, nodelete;
  382.     FILE    *nfile;
  383.  
  384.     if (m->mfile == NULLFILE)
  385.         return 0;
  386.  
  387.     if(!m->change) {        /* no changes were made */
  388.         mfclose(m);
  389.         m->mboxsize = 0;
  390.         return 0;
  391.     }
  392.     /* If this area is a public message area, then we will not add a
  393.      * Status line to indicate that the message has been read.
  394.      */
  395.     nostatus = isarea(m->area);
  396.  
  397.     /* Don't delete messages from public message areas unless you are
  398.      * a BBS.
  399.      */
  400.     if(nostatus)
  401.         nodelete = !(m->privs & SYSOP_CMD);
  402.     else
  403.         nodelete = 0;
  404.  
  405.     /* See if any messages have been forwarded, otherwise just close
  406.      * the file and return since there is nothing to write back.
  407.      */
  408.     if(nostatus && nodelete) {
  409.         for(i=1; i <= m->nmsgs; ++i)
  410.             if(m->mbox[i].status & BM_FORWARDED)
  411.                 break;
  412.         if(i > m->nmsgs) {
  413.             mfclose(m);
  414.             m->mboxsize = 0;
  415.             return 0;
  416.         }
  417.     }
  418.     line = tstring;
  419.     scanmail(m);
  420.     if(lockit(m))
  421.         return -1;
  422.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  423.     if ((nfile = fopen(buf,WRITE_TEXT)) == NULLFILE) {
  424.         tprintf(Noaccess,buf);
  425.         mfclose(m);
  426.         m->mboxsize = 0;
  427.         rmlock(Mailspool,m->area);
  428.         return -1;
  429.     }
  430.     /* copy tmp file back to notes file */
  431.     for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++) {
  432.         fseek(m->mfile,cmsg->start,0);
  433.         size = cmsg->size;
  434.         /* It is not possible to delete messages if nodelete is set */
  435.         if ((cmsg->status & BM_DELETE) && !nodelete)
  436.             continue;
  437.         /* copy the header */
  438.         while (size > 0 && fgets(line,LINELEN,m->mfile) != NULLCHAR) {
  439.             size -= strlen(line);
  440.             if (*line == '\n') {
  441.                 if (cmsg->status & BM_FORWARDED)
  442.                     fprintf(nfile,"%s%s\n",Hdrs[XFORWARD],
  443.                         m->name);
  444.                 if ((cmsg->status & BM_READ) != 0 && !nostatus)
  445.                     fprintf(nfile,"%sR\n",Hdrs[STATUS]);
  446.                 fprintf(nfile,"\n");
  447.                 break;
  448.             }
  449.             fputs(line,nfile);
  450.             /* pwait(NULL);  can cause problems if exiting NOS */
  451.         }
  452.         while (size > 0 && fgets(line,LINELEN,m->mfile) != NULLCHAR) {
  453.             fputs(line,nfile);
  454.             size -= strlen(line);
  455.             /* pwait(NULL);   dont want no damaged files */
  456.             if (ferror(nfile)) {
  457.                 tprintf("Error writing mail file\n");
  458.                 (void) fclose(nfile);
  459.                 mfclose(m);
  460.                 m->mboxsize = 0;
  461.                 rmlock(Mailspool,m->area);
  462.                 return -1;
  463.             }
  464.         }
  465.     }
  466.     m->nmsgs = 0;
  467.     if (!stricmp(m->name,m->area))
  468.         m->mysize = ftell(nfile); /* Update the size of our mailbox */
  469.     /* remove a zero length file */
  470.     if (ftell(nfile) == 0L)
  471.         (void) unlink(buf);
  472.     (void) fclose(nfile);
  473.     mfclose(m);
  474.     m->mboxsize = 0;
  475.     rmlock(Mailspool,m->area);
  476.     pwait(NULL);
  477.     return 0;
  478. }
  479.  
  480. /* Returns 1 if name is a public message Area, 0 otherwise */
  481. int
  482. isarea(name)
  483. char *name;
  484. {
  485.     char buf[LINELEN], *cp;
  486.     FILE *fp;
  487.     if((fp = fopen(Arealist,READ_TEXT)) == NULLFILE)
  488.         return 0;
  489.     while(fgets(buf,sizeof(buf),fp) != NULLCHAR) {
  490.         /* The first word on each line is all that matters */
  491.         if((cp = strchr(buf,' ')) == NULLCHAR)
  492.             if((cp = strchr(buf,'\t')) == NULLCHAR)
  493.                 continue;
  494.         *cp = '\0';
  495.         if((cp = strchr(buf,'\t')) != NULLCHAR)
  496.             *cp = '\0';
  497.         if(stricmp(name,buf) == 0) {    /* found it */
  498.             fclose(fp);
  499.             return 1;
  500.         }
  501.     }
  502.     fclose(fp);
  503.     return 0;
  504. }
  505.  
  506. static int lockit(struct mbx *m)
  507. {
  508.     int c, cnt = 0;
  509.  
  510.     while(mlock(Mailspool,m->area)) {
  511.         Pause(1000L/MSPTICK);    /* Wait one second */
  512.         if(++cnt == 10) {
  513.             cnt = 0;
  514.             c = tkeywait("Mail file is busy, Abort or Retry ? ",1);
  515.             if (c == 'A' || c == 'a' || c == EOF) {
  516.                 mfclose(m);
  517.                 return 1;
  518.             }
  519.         }
  520.     }
  521.     return 0;
  522. }
  523.  
  524. /* read the next message or the current one if new */
  525. int
  526. doreadnext(argc,argv,p)
  527. int argc;
  528. char *argv[];
  529. void *p;
  530. {
  531.     struct mbx *m;
  532.     char buf[10], *newargv[2];
  533.     m = (struct mbx *) p;
  534.     if (m->mfile == NULLFILE)
  535.         return 0;
  536.     if ((m->mbox[m->current].status & BM_READ) != 0) {
  537.         if (m->current == 1 && m->anyread == 0)
  538.             ;
  539.         else if (m->current < m->nmsgs) {
  540.             m->current++;
  541.         } else {
  542.             tprintf("Last message\n");
  543.             return 0;
  544.         }
  545.     }
  546.     sprintf(buf,"%d",m->current);
  547.     newargv[0] = "read";
  548.     newargv[1] = buf;
  549.     m->anyread = 1;
  550.     return doreadmsg(2,newargv,p);
  551. }
  552.  
  553. /*  display message on the crt given msg number */
  554. int
  555. doreadmsg(argc,argv,p)
  556. int argc;
  557. char *argv[];
  558. void *p;
  559. {
  560.     struct mbx *m;
  561.     register int c, col, lin;
  562.     char    buf[MAXCOL+2], *cp, *cp2;
  563.     int    msg, cnt, i, usemore, verbose, mbxheader, pathcol;
  564.     int    header, lastheader;
  565.     long     size;
  566.  
  567.     m = (struct mbx *) p;
  568.     if (m->mfile == NULLFILE) {
  569.         tprintf(Nomail);
  570.         return 0;
  571.     }
  572.     if(m->type == TELNET || m->type == TIP)
  573.         usemore = 1;    /* Display More prompt */
  574.     else
  575.         usemore = 0;
  576.     lin = MAXLIN-1;
  577.     for(i = 1; i < argc; ++i) {
  578.         msg = atoi(argv[i]);
  579.         if( msg < 1 || msg > m->nmsgs) {
  580.             tprintf(Badmsg,msg);
  581.             return 0;
  582.         }
  583.         fseek(m->mfile,m->mbox[msg].start,0);
  584.         size = m->mbox[msg].size;
  585.         m->current = msg;
  586.         header = NOHEADER;
  587.         mbxheader = 0;
  588.         if(*argv[0] == 'v')
  589.             verbose = 1;    /* display all header lines */
  590.         else
  591.             verbose = 0;
  592.  
  593.         tprintf("Message #%d %s\n", msg,
  594.             m->mbox[msg].status & BM_DELETE ? "[Deleted]" : "");
  595.         if ((m->mbox[msg].status & BM_READ) == 0) {
  596.             m->mbox[msg].status |= BM_READ;
  597.             m->change = 1;
  598.             m->newmsgs--;
  599.         }
  600.         --lin;
  601.         col = 0;
  602.         while (!feof(m->mfile) && size > 0) {
  603.             for (col = 0;  col < MAXCOL;) {
  604.                 c = getc(m->mfile);
  605.                 size--;
  606.                 if (feof(m->mfile) || size == 0) /* end this line */
  607.                     break;
  608.                 if (c == '\t') {
  609.                     cnt = col + 8 - (col & 7);
  610.                     if (cnt >= MAXCOL) /* end this line */
  611.                         break;
  612.                     while (col < cnt)
  613.                         buf[col++] = ' ';
  614.                 } else {
  615.                     if (c == '\n')
  616.                         break;
  617.                     buf[col++] = c;
  618.                 }
  619.             }
  620.             if(col < MAXCOL)
  621.                 buf[col++] = '\n';
  622.             buf[col] = '\0';
  623.             if(mbxheader > 0) {
  624.                  /* Digest R: lines and display as a Path: line */
  625.                  if(strncmp(buf,"R:",2) != 0 ||
  626.                 (cp = strchr(buf,'@')) == NULLCHAR) {
  627.                   tputc('\n');
  628.                   mbxheader = -1; /* don't get here again */
  629.                   verbose = 1;
  630.                  }
  631.                  else {
  632.                   if(*(++cp) == ':')
  633.                        ++cp;
  634.                   for(cp2 = cp; isalnum(*cp2); ++cp2)  ;
  635.                   *cp2 = '\0';
  636.                   if(mbxheader++ == 1) {
  637.                        tputs("Path: ");
  638.                        pathcol = 5;
  639.                        --lin;
  640.                   }
  641.                   else {
  642.                        tputc('!');
  643.                        if(++pathcol + strlen(cp) > MAXCOL-3){
  644.                         tputs("\n      ");
  645.                         pathcol = 5;
  646.                         --lin;
  647.                        }
  648.                   }
  649.                   tputs(cp);
  650.                   pathcol += strlen(cp);
  651.                   ++lin;    /* to allow for not printing it later */
  652.                  }
  653.             }
  654.             if(col == 1 && !verbose && !mbxheader)
  655.                  /* last header line reached */
  656.                  mbxheader = 1;
  657.             if(verbose)
  658.                 tputs(buf);
  659.             if(!verbose && !mbxheader){
  660.                 lastheader = header;
  661.                 if(!isspace(*buf))
  662.                     header = htype(buf);
  663.                 else
  664.                     header = lastheader;
  665.                 switch(header) {
  666.                 case TO:
  667.                 case CC:
  668.                 case FROM:
  669.                 case DATE:
  670.                 case SUBJECT:
  671.                 case APPARTO:
  672.                 case ORGANIZATION:
  673.                     tputs(buf);
  674.                     break;
  675.                 default:
  676.                     ++lin;
  677.                 }
  678.             }
  679.             col = 0;
  680.             if(usemore && --lin == 0){
  681.                 c = tkeywait("--More--",0);
  682.                 lin = MAXLIN-1;
  683.                 if(c == -1 || c == 'q' || c == 'Q')
  684.                     break;
  685.                 if(c == '\n' || c == '\r')
  686.                     lin = 1;
  687.             }
  688.         }
  689.     }
  690.     return 0;
  691. }
  692.  
  693. /* Set up m->to when replying to a message. The subject is returned in
  694.  * m->line.
  695.  */
  696. int mbx_reply(int argc,char *argv[],struct mbx *m,struct list **cclist,char **rhdr)
  697. {
  698.     char subject[MBXLINE], *msgid = NULLCHAR, *date = NULLCHAR;
  699.     char *cp;
  700.     int msg, lastheader, header = NOHEADER;
  701.     long size;
  702.  
  703.     /* Free anything that might be allocated
  704.      * since the last call to mbx_to() or mbx_reply()
  705.      */
  706.     free(m->to);
  707.     m->to = NULLCHAR;
  708.     free(m->tofrom);
  709.     m->tofrom = NULLCHAR;
  710.     free(m->tomsgid);
  711.     m->tomsgid = NULLCHAR;
  712.     free(m->origto);
  713.     m->origto = NULLCHAR;
  714.     subject[0] = '\0';
  715.  
  716.     if(argc == 1)
  717.          msg = m->current;
  718.     else
  719.          msg = atoi(argv[1]);
  720.     if (m->mfile == NULLFILE) {
  721.          if(m->sid & MBX_SID)
  722.           tputs("NO - ");
  723.         tputs(Nomail);
  724.         return 0;
  725.     }
  726.     if(msg < 1 || msg > m->nmsgs) {
  727.          if(m->sid & MBX_SID)
  728.           tputs("NO - ");
  729.          tputs(Badmsg);
  730.          return -1;
  731.     }
  732.     fseek(m->mfile,m->mbox[msg].start,0);
  733.     size = m->mbox[msg].size;
  734.     m->current = msg;
  735.     while(size > 0 && fgets(m->line,MBXLINE-1,m->mfile) != NULLCHAR) {
  736.          size -= strlen(m->line);
  737.          if(m->line[0] == '\n')    /* end of header */
  738.           break;
  739.          rip(m->line);
  740.          lastheader = header;
  741.          if(!isspace(m->line[0])) {
  742.           header = htype(m->line);
  743.           lastheader = NOHEADER;
  744.          }
  745.          switch(header) {
  746.          case SUBJECT:
  747.           if(strlen(m->line) > 11 && !strnicmp(&m->line[9],"Re:",3))
  748.                strcpy(subject,&m->line[9]);
  749.           else
  750.                sprintf(subject,"Re: %s",&m->line[9]);
  751.           break;
  752.          case FROM:
  753.           if(m->to == NULLCHAR && (cp = getaddress(m->line,0)) !=
  754.              NULLCHAR)
  755.                m->to = strdup(cp);
  756.           break;
  757.          case REPLYTO:
  758.           if((cp = getaddress(m->line,0)) != NULLCHAR) {
  759.                free(m->to);
  760.                m->to = strdup(cp);
  761.           }
  762.           break;
  763.          case MSGID:
  764.           free(msgid);
  765.           msgid = strdup(&m->line[12]);
  766.           break;
  767.          case DATE:
  768.           free(date);
  769.           date = strdup(&m->line[6]);
  770.           break;
  771.          case TO:
  772.          case CC:
  773.          case APPARTO:
  774.           /* Get addresses on To, Cc and Apparently-To lines */
  775.           cp = m->line;
  776.           m->line[strlen(cp)+1] = '\0';    /* add extra null at end */
  777.           for(;;) {
  778.                if((cp = getaddress(cp,lastheader == header ||
  779.                        cp != m->line)) == NULLCHAR)
  780.                 break;
  781.                addlist(cclist,cp,0);
  782.                /* skip to next address, if any */
  783.                cp += strlen(cp) + 1;
  784.           }
  785.           break;
  786.          }
  787.     }
  788.     if(msgid != NULLCHAR || date != NULLCHAR) {
  789.          *rhdr = mallocw(LINELEN);
  790.          sprintf(*rhdr,"In-Reply-To: your message ");
  791.          if(date != NULLCHAR) {
  792.           sprintf(m->line,"of %s.\n",date);
  793.           strcat(*rhdr,m->line);
  794.           if(msgid != NULLCHAR)
  795.                strcat(*rhdr,"             ");
  796.          }
  797.          if(msgid != NULLCHAR) {
  798.           sprintf(m->line,"%s\n",msgid);
  799.           strcat(*rhdr,m->line);
  800.          }
  801.          free(msgid);
  802.          free(date);
  803.     }
  804.     strcpy(m->line,subject);
  805.     return 0;
  806. }
  807.  
  808. void scanmail(struct mbx *m)         /* Get any new mail */
  809. {
  810.     FILE *nfile;
  811.     int ret, cnt;
  812.     char buf[256];
  813.     long diff;
  814.  
  815.     if ((diff = isnewmail(m)) == 0L)
  816.         return;
  817.     if(lockit(m))
  818.         return;
  819.     if(m->mfile == NULLFILE || diff < 0L) {
  820.         /* This is the first time scanmail is called, or the
  821.          * mail file size has decreased. In the latter case,
  822.          * any changes we did to this area will be lost, but this
  823.          * is not fatal.
  824.          */
  825.         initnotes(m);
  826.         rmlock(Mailspool,m->area);
  827.         return;
  828.     }
  829.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  830.     if ((nfile = fopen(buf,READ_TEXT)) == NULLFILE)
  831.         tprintf(Noaccess,buf);
  832.     else {
  833.         /* rewind tempfile */
  834.         fseek(m->mfile,0L,0);
  835.         cnt = m->nmsgs;
  836.         /* Reread all messages since size they may have changed
  837.          * in size after a X-Forwarded-To line was added.
  838.          */
  839.         m->nmsgs = 0;
  840.         ret = readnotes(m,nfile,1);   /* get the mail */
  841.         m->newmsgs += m->nmsgs - cnt;
  842.         m->mboxsize = ftell(nfile);
  843.         if(!stricmp(m->name,m->area))
  844.             m->mysize = m->mboxsize;
  845.         (void) fclose(nfile);
  846.         if (ret != 0)
  847.             tprintf("Error updating mail file\n");
  848.     }
  849.     rmlock(Mailspool,m->area);
  850. }
  851.  
  852. /* Check the current mailbox to see if new mail has arrived.
  853.  * Returns the difference in size.
  854.  */
  855. static long isnewmail(struct mbx *m)
  856. {
  857.     char buf[256];
  858.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  859.     return fsize(buf) - m->mboxsize;
  860. }
  861.  
  862. /* Check if the private mail area has changed */
  863. long isnewprivmail(struct mbx *m)
  864. {
  865.     long cnt;
  866.     char buf[256];
  867.     sprintf(buf,"%s/%s.txt",Mailspool,m->name);
  868.     cnt = m->mysize;
  869.     m->mysize = fsize(buf);
  870.     return m->mysize - cnt; /* != 0 not more than once */
  871. }
  872.  
  873. char *Hdrs[] = {
  874.     "Approved: ",
  875.     "From: ",
  876.     "To: ",
  877.     "Date: ",
  878.     "Message-Id: ",
  879.     "Subject: ",
  880.     "Received: ",
  881.     "Sender: ",
  882.     "Reply-To: ",
  883.     "Status: ",
  884.     "X-BBS-Msg-Type: ",
  885.     "X-Forwarded-To: ",
  886.     "Cc: ",
  887.     "Return-Receipt-To: ",
  888.     "Apparently-To: ",
  889.     "Errors-To: ",
  890.     "Organization: ",
  891.     NULLCHAR
  892. };
  893.  
  894. /* return the header type */
  895. int
  896. htype(s)
  897. char *s;
  898. {
  899.     register char *p;
  900.     register int i;
  901.  
  902.     p = s;
  903.     /* check to see if there is a ':' before and white space */
  904.     while (*p != '\0' && *p != ' ' && *p != ':')
  905.         p++;
  906.     if (*p != ':')
  907.         return NOHEADER;
  908.  
  909.     for (i = 0; Hdrs[i] != NULLCHAR; i++) {
  910.         if (strnicmp(Hdrs[i],s,strlen(Hdrs[i])) == 0)
  911.             return i;
  912.     }
  913.     return UNKNOWN;
  914. }
  915.  
  916. /* This function returns the length of a file. The proper thing would be
  917.  * to use stat(), but it fails when using DesqView together with Turbo-C
  918.  * code.
  919.  */
  920. static long
  921. fsize(name)
  922. char *name;
  923. {
  924.     long cnt;
  925.     FILE *fp;
  926.     if((fp = fopen(name,READ_TEXT)) == NULLFILE)
  927.         return -1L;
  928.     fseek(fp,0L,2);
  929.     cnt = ftell(fp);
  930.     fclose(fp);
  931.     return cnt;
  932. }
  933.  
  934. /* close the temporary mail file */
  935. static void mfclose(struct mbx *m)
  936. {
  937.     if(m->mfile != NULLFILE)
  938.         fclose(m->mfile);
  939.     m->mfile = NULLFILE;
  940. #ifdef SETVBUF
  941.     free(m->stdoutbuf);
  942.     m->stdoutbuf = NULLCHAR;
  943. #endif
  944. }
  945.  
  946. /* Parse a string in the "Text: <user@host>" or "Text: user@host (Text)"
  947.  * format for the address user@host.
  948.  */
  949. char *
  950. getaddress(string,cont)
  951. char *string;
  952. int cont;        /* true if string is a continued header line */
  953. {
  954.     char *cp, *ap = NULLCHAR;
  955.     int par = 0;
  956.     if((cp = getname(string)) != NULLCHAR) /* Look for <> style address */
  957.          return cp;
  958.     cp = string;
  959.     if(!cont)
  960.          if((cp = strchr(string,':')) == NULLCHAR)    /* Skip the token */
  961.           return NULLCHAR;
  962.          else
  963.           ++cp;
  964.     for(; *cp != '\0'; ++cp) {
  965.          if(par && *cp == ')') {
  966.           --par;
  967.           continue;
  968.          }
  969.          if(*cp == '(')        /* Ignore text within parenthesis */
  970.           ++par;
  971.          if(par)
  972.           continue;
  973.          if(*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == ',') {
  974.           if(ap != NULLCHAR)
  975.                break;
  976.           continue;
  977.          }
  978.          if(ap == NULLCHAR)
  979.           ap = cp;
  980.     }
  981.     *cp = '\0';
  982.     return ap;
  983. }
  984.  
  985. /* Print prompt and read one character, telnet version */
  986. static int
  987. tkeywait(prompt,flush)
  988. char *prompt;    /* Optional prompt */
  989. int flush;    /* Flush queued input? */
  990. {
  991.     int c, i, oldimode,oldomode;
  992.  
  993.     if(flush && socklen(Curproc->input,0) != 0)
  994.         recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0); /* flush */
  995.     if(prompt == NULLCHAR)
  996.         prompt = "Hit enter to continue"; 
  997.     tprintf("%s%c%c%c",prompt,IAC,WILL,TN_ECHO);
  998.     usflush(Curproc->output);
  999.  
  1000.     /* discard the response */
  1001.  
  1002.     oldimode = sockmode(Curproc->input,SOCK_BINARY);
  1003.     oldomode = sockmode(Curproc->output,SOCK_BINARY);
  1004.  
  1005.     while((c = rrecvchar(Curproc->input)) == IAC){
  1006.         c = rrecvchar(Curproc->input);
  1007.         if(c > 250 && c < 255)
  1008.             rrecvchar(Curproc->input);
  1009.     }
  1010.  
  1011.     sockmode(Curproc->output,oldomode);
  1012.     sockmode(Curproc->input,oldimode);
  1013.  
  1014.     /* Get rid of the prompt */
  1015.     for(i=strlen(prompt);i != 0;i--)
  1016.         tputc('\b');
  1017.     for(i=strlen(prompt);i != 0;i--)
  1018.         tputc(' ');
  1019.     for(i=strlen(prompt);i != 0;i--)
  1020.         tputc('\b');
  1021.     tprintf("%c%c%c",IAC,WONT,TN_ECHO);
  1022.     usflush(Curproc->output);
  1023.     return c;
  1024. }
  1025.